home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Magazin/MacEasy 11
/
Mac Magazin and MacEasy Magazine CD - Issue 11.iso
/
Sharewarebibliothek
/
Entwickler
/
WASTE 1.1b1 Distribution
/
WASTE Source
/
WEMouse.p
< prev
next >
Wrap
Text File
|
1995-06-01
|
32KB
|
1,172 lines
unit WEMouse;
{ WASTE PROJECT }
{ Mouse Clicks and support for Drag and Drop }
{ Copyright © 1993-1995 Marco Piovanelli }
{ All Rights Reserved }
interface
uses
WEBirthDeath;
procedure WEClick (mouseLoc: Point;
modifiers: Integer;
clickTime: LongInt;
hWE: WEHandle);
function WETrackDrag (theMessage: DragTrackingMessage;
theDrag: DragReference;
hWE: WEHandle): OSErr;
function WEReceiveDrag (theDrag: DragReference;
hWE: WEHandle): OSErr;
function WECanAcceptDrag (theDrag: DragReference;
hWE: WEHandle): Boolean;
function WEDraggedToTrash (theDrag: DragReference): Boolean;
implementation
uses
Folders, WEScraps;
const
noDragErr = 128;
kTextMargin = 3; { width of border area surrounding the text (in pixels) }
kAutoScrollDelay = 10; { delay before auto-scroll starts (in ticks) }
{$IFC WASTE_SEGMENT}
{$S WASTE_DRAG}
{$ENDC}
var
{ static variables }
_weFlavorSender: DragSendDataUPP;
function _WEIsOptionDrag (theDrag: DragReference): Boolean;
var
modifiers, downModifiers, upModifiers: Integer;
begin
{ get drag modifiers }
if (GetDragModifiers(theDrag, modifiers, downModifiers, upModifiers) <> noErr) then
;
{ return TRUE if the option key was held down at the beginning and/or at the end }
_WEIsOptionDrag := BAND(BOR(downModifiers, upModifiers), optionKey) <> 0;
end; { _WEIsOptionDrag }
function _WEGetFlavor (theDrag: DragReference;
theItem: ItemReference;
requestedType: FlavorType;
hFlavor: Handle;
translateDragHook: ProcPtr): OSErr;
{ get the requested flavor out of the specified drag reference and put it into }
{ the given handle, if any -- if hFlavor is NIL, just check whether the specified flavor }
{ is there or can be obtained by invoking a user-defined translation routine }
label
1;
var
theFlags: FlavorFlags;
theSize: Size;
saveFlavorLock: Boolean;
err: OSErr;
begin
{ see if the drag item has the requested flavor type, }
{ without forcing the actual data to be sent and/or translated }
err := GetFlavorFlags(theDrag, theItem, requestedType, theFlags);
if (err = badDragFlavorErr) then
begin
{ requested flavor is not available: our client may try a custom translation }
{ this is especially handy to translate HFS objects like TEXT and PICT files }
if (translateDragHook <> nil) then
err := CallWETranslateDragProc(theDrag, theItem, requestedType, hFlavor, translateDragHook);
end
else if (err = noErr) then
begin
{ requested flavor is available: get it if hFlavor is not NIL }
if (hFlavor = nil) then
goto 1;
{ get size of flavor data }
err := GetFlavorDataSize(theDrag, theItem, requestedType, theSize);
if (err <> noErr) then
goto 1;
{ resize the handle }
SetHandleSize(hFlavor, theSize);
err := MemError;
if (err <> noErr) then
goto 1;
{ get flavor data }
saveFlavorLock := _WESetHandleLock(hFlavor, true);
err := GetFlavorData(theDrag, theItem, requestedType, hFlavor^, theSize, 0);
if (_WESetHandleLock(hFlavor, saveFlavorLock)) then
;
end;
1:
{ return result code }
_WEGetFlavor := err;
end; { _WEGetFlavor }
function _WEExtractFlavor (theDrag: DragReference;
theItem: ItemReference;
theType: FlavorType;
var hFlavor: Handle;
translateDragHook: ProcPtr): OSErr;
{ _WEExtractFlavor creates a new handle and calls _WEGetFlavor on it }
var
err: OSErr;
begin
{ allocate a new handle }
err := _WEAllocate(0, kAllocTemp, hFlavor);
if (err = noErr) then
begin
{ put the requested flavor into this handle }
err := _WEGetFlavor(theDrag, theItem, theType, hFlavor, translateDragHook);
{ if an error occurred, forget the handle }
if (err <> noErr) then
_WEForgetHandle(hFlavor);
end;
_WEExtractFlavor := err;
end; { _WEExtractFlavor }
function WECanAcceptDrag (theDrag: DragReference;
hWE: WEHandle): Boolean;
label
1;
var
pWE: WEPtr;
dragItemIndex, numDragItems: Integer;
theItem: ItemReference;
objectIndex: Integer;
objectType: OSType;
saveWELock: Boolean;
err: OSErr;
begin
WECanAcceptDrag := false; { assume drag can't be accepted }
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ refuse all drags if the weFReadOnly flag is set }
if (BTST(pWE^.flags, weFReadOnly)) then
goto 1;
{ count items in theDrag }
if (CountDragItems(theDrag, numDragItems) <> noErr) then
goto 1;
for dragItemIndex := 1 to numDragItems do
begin
{ get item reference number for current drag item }
if (GetDragItemReferenceNumber(theDrag, dragItemIndex, theItem) <> noErr) then
goto 1;
{ see if this drag item contains a text flavor }
err := _WEGetFlavor(theDrag, theItem, kTypeText, nil, pWE^.translateDragHook);
if (err = badDragFlavorErr) then
begin
{ see if this drag item contains a flavor matching one of the registered object types }
objectIndex := 0;
while (_WEGetIndObjectType(objectIndex, objectType, hWE) = noErr) do
begin
err := _WEGetFlavor(theDrag, theItem, objectType, nil, pWE^.translateDragHook);
if (err <> badDragFlavorErr) then
Leave; { enclosing while }
objectIndex := objectIndex + 1;
end; { while }
end;
if (err <> noErr) then
goto 1;
end; { for }
WECanAcceptDrag := true;
1:
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WECanAcceptDrag }
procedure _WEUpdateDragCaret (offset: LongInt;
hWE: WEHandle);
var
ticks: LongInt;
pWE: WEPtr;
begin
{ the WE record must be already locked }
pWE := hWE^;
{ get current time }
ticks := TickCount;
if (offset = pWE^.dragCaretOffset) then
begin
{ drag caret offset didn't change; blink the caret }
if (GetCaretTime < ticks - pWE^.caretTime) and (offset <> kInvalidOffset) then
begin
_WEDrawCaret(pWE^.dragCaretOffset, hWE);
pWE^.flags := BXOR(pWE^.flags, BSL(1, weFDragCaretVisible));
pWE^.caretTime := ticks;
end;
end
else
begin
{ drag caret offset did change }
{ hide old caret, if it's showing }
if BTST(pWE^.flags, weFDragCaretVisible) then
_WEDrawCaret(pWE^.dragCaretOffset, hWE);
{ show new caret (unless offset is kInvalidOffset) }
if (offset <> kInvalidOffset) then
begin
_WEDrawCaret(offset, hWE);
BSET(pWE^.flags, weFDragCaretVisible);
pWE^.caretTime := ticks;
end
else
BCLR(pWE^.flags, weFDragCaretVisible);
{ remember drag caret offset }
pWE^.dragCaretOffset := offset;
end;
end; { _WEUpdateDragCaret }
function WETrackDrag (theMessage: DragTrackingMessage;
theDrag: DragReference;
hWE: WEHandle): OSErr;
label
1;
var
pWE: WEPtr;
attributes: DragAttributes;
mouse: Point;
tmpRgn: RgnHandle;
thePoint: LongPt;
offset, ticks: LongInt;
edge: SignedByte;
saveWELock: Boolean;
err: OSErr;
begin
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ dispatch on theMessage }
case theMessage of
dragTrackingEnterWindow:
begin
{ determine whether we can accept this drag }
if (WECanAcceptDrag(theDrag, hWE)) then
BSET(pWE^.flags, weFCanAcceptDrag)
else
BCLR(pWE^.flags, weFCanAcceptDrag);
{ reset clickTime }
pWE^.clickTime := 0;
end;
dragTrackingInWindow:
if BTST(pWE^.flags, weFCanAcceptDrag) then
begin
{ get drag attributes }
err := GetDragAttributes(theDrag, attributes);
if (err <> noErr) then
goto 1;
{ get current mouse location in local coordinates }
err := GetDragMouse(theDrag, mouse, PointPtr(0)^);
if (err <> noErr) then
goto 1;
GlobalToLocal(mouse);
if (PtInRgn(mouse, pWE^.viewRgn)) then
begin
{ mouse is in text area }
{ hilite the text rectangle, if we haven't already }
{ and if the drag has left sender window since drag tracking started }
if ((not BTST(pWE^.flags, weFHilited)) and (BAND(attributes, dragHasLeftSenderWindow) <> 0)) then
begin
tmpRgn := NewRgn;
CopyRgn(pWE^.viewRgn, tmpRgn);
InsetRgn(tmpRgn, -kTextMargin, -kTextMargin);
if (ShowDragHilite(theDrag, tmpRgn, true) <> noErr) then
;
DisposeRgn(tmpRgn);
BSET(pWE^.flags, weFHilited);
end;
{ hide the caret }
if BTST(pWE^.flags, weFCaretVisible) then
_WEBlinkCaret(hWE);
{ get text offset corresponding to mouse location }
WEPointToLongPoint(mouse, thePoint);
offset := WEGetOffset(thePoint, edge, hWE);
{ if offset is within the original selection range, don't display drag feedback }
if (theDrag = pWE^.currentDrag) then
if (_WEOffsetInRange(offset, edge, pWE^.selStart, pWE^.selEnd)) then
offset := kInvalidOffset;
{ provide a drag feedback in the form of a blinking caret }
_WEUpdateDragCaret(offset, hWE);
{ clear clickTime }
pWE^.clickTime := 0;
end
else
begin
{ mouse is outside text area }
{ dehilite the text rectangle, if it's hilited }
if (BTST(pWE^.flags, weFHilited)) then
begin
if (HideDragHilite(theDrag) <> noErr) then
;
BCLR(pWE^.flags, weFHilited);
end;
{ hide the drag caret, if it's showing }
_WEUpdateDragCaret(kInvalidOffset, hWE);
{ if the mouse has been remaining outside the view region for 10 ticks or more }
{ and this drag was created by this WE instance, call the click loop routine }
if (theDrag = pWE^.currentDrag) then
begin
ticks := TickCount;
if (pWE^.clickTime = 0) then
pWE^.clickTime := ticks
else if (ticks > pWE^.clickTime + kAutoScrollDelay) then
if (pWE^.clickLoop <> nil) then
if (CallWEClickLoopProc(hWE, pWE^.clickLoop)) then
;
end;
end;
end; { case dragTrackingInWindow }
dragTrackingLeaveWindow:
begin
{ drag has left this window }
{ dehilite the text area if necessary }
if (BTST(pWE^.flags, weFHilited)) then
begin
if (HideDragHilite(theDrag) <> noErr) then
;
BCLR(pWE^.flags, weFHilited);
end;
{ hide the drag caret, if it's showing }
_WEUpdateDragCaret(kInvalidOffset, hWE);
end;
otherwise
;
end; { case theMessage }
{ clear result code }
err := noErr;
1:
{ return result code }
WETrackDrag := err;
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WETrackDrag }
function WEReceiveDrag (theDrag: DragReference;
hWE: WEHandle): OSErr;
label
1;
var
pWE: WEPtr;
hAction: WEActionHandle;
mouse: Point;
dropLocation: LongPt;
insertionOffset, insertionLength: LongInt;
sourceStart, sourceEnd: LongInt;
destStart, destEnd: LongInt;
delta: LongInt;
dragItemIndex, numDragItems: Integer;
theItem: ItemReference;
hText, hStyles, hSoup, hObjectData: Handle;
objectIndex: Integer;
objectType: OSType;
savePort: GrafPtr;
intPasteAction: Integer;
saveUndoSupport, saveInhibitRecal: Integer;
dropEdge, space: SignedByte;
isMove, isBackwards: Boolean;
saveWELock: Boolean;
err: OSErr;
begin
isMove := false;
hText := nil;
hStyles := nil;
hSoup := nil;
hObjectData := nil;
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ set up the port }
GetPort(savePort);
SetPort(pWE^.port);
{ stop any ongoing inline input session }
WEStopInlineSession(hWE);
{ hide the drag caret }
_WEUpdateDragCaret(kInvalidOffset, hWE);
{ refuse this drag if it doesn't taste good }
err := badDragFlavorErr;
if (WECanAcceptDrag(theDrag, hWE) = false) then
goto 1;
{ get drop location in local coordinates }
err := GetDragMouse(theDrag, mouse, PointPtr(0)^);
if (err <> noErr) then
goto 1;
GlobalToLocal(mouse);
{ for the drag to be accepted, the drop location must be within the view region }
err := dragNotAcceptedErr;
if (PtInRgn(mouse, pWE^.viewRgn) = false) then
goto 1;
{ get drop offset into the text }
WEPointToLongPoint(mouse, dropLocation);
insertionOffset := WEGetOffset(dropLocation, dropEdge, hWE);
{ destStart/destEnd define the range to highlight at the end of the drag }
destStart := insertionOffset;
{ drag originated from this same window? }
if (theDrag = pWE^.currentDrag) then
begin
{ sourceStart/sourceEnd define the range to delete at the end of the move }
sourceStart := pWE^.selStart;
sourceEnd := pWE^.selEnd;
{ remember text length before insertion }
delta := pWE^.textLength;
{ if insertion offset is within the original selection range, abort the drag }
(*err := dragNotAcceptedErr;*)
if (_WEOffsetInRange(insertionOffset, dropEdge, sourceStart, sourceEnd)) then
goto 1;
{ if the drag originated from this window, a move, }
{ rather than a copy, should be performed }
{ Exception: the option key may be held down at mouse-down }
{ or mouse-up time to force a copy operation. }
isMove := (_WEIsOptionDrag(theDrag) = false);
isBackwards := (insertionOffset <= sourceStart);
end; { if intra-window drag }
{ clear null style }
BCLR(pWE^.flags, weFUseNullStyle);
{ hide selection highlighting }
_WEHiliteRange(pWE^.selStart, pWE^.selEnd, hWE);
{ increment modification count }
pWE^.modCount := pWE^.modCount + 1;
{ if undo support is enabled, create a new action so we'll be able to undo the insertion }
if (BTST(pWE^.flags, weFUndoSupport)) then
begin
WEClearUndo(hWE);
if (WENewAction(insertionOffset, insertionOffset, 0, weAKDrag, 0, hWE, hAction) = noErr) then
if (WEPushAction(hAction) <> noErr) then
;
end;
{ count items in this drag }
err := CountDragItems(theDrag, numDragItems);
if (err <> noErr) then
goto 1;
for dragItemIndex := 1 to numDragItems do
begin
{ get item reference number for current drag item }
err := GetDragItemReferenceNumber(theDrag, dragItemIndex, theItem);
if (err <> noErr) then
goto 1;
{ see if this drag item contains a text flavor }
err := _WEExtractFlavor(theDrag, theItem, kTypeText, hText, pWE^.translateDragHook);
if (err = noErr) then
begin
{ extract accompanying styles and soup, if any }
err := _WEExtractFlavor(theDrag, theItem, kTypeStyles, hStyles, pWE^.translateDragHook);
if (err <> noErr) and (err <> badDragFlavorErr) then
goto 1;
err := _WEExtractFlavor(theDrag, theItem, kTypeSoup, hSoup, pWE^.translateDragHook);
if (err <> noErr) and (err <> badDragFlavorErr) then
goto 1;
{ any extra space added because of intelligent cut-and-paste rules will use the }
{ style attributes set at the insertion point }
if (dragItemIndex = 1) then
begin
pWE^.selStart := insertionOffset;
pWE^.selEnd := insertionOffset;
_WESynchNullStyle(hWE);
end;
{ get text length }
insertionLength := GetHandleSize(hText);
destEnd := insertionOffset + insertionLength;
{ insert the new text at the insertion point }
HLock(hText);
err := _WEInsertText(insertionOffset, hText^, insertionLength, hWE);
_WEForgetHandle(hText);
if (err <> noErr) then
goto 1;
{ adjust deletion range length in undo buffer }
_WEAdjustUndoRange(insertionLength, hWE);
{ apply the accompanying styles, if any }
if (hStyles <> nil) then
begin
err := _WEApplyStyleScrap(insertionOffset, destEnd, StScrpHandle(hStyles), hWE);
if (err <> noErr) then
goto 1;
_WEForgetHandle(hStyles);
end;
{ apply the accompanying soup, if any }
if (hSoup <> nil) then
begin
err := _WEApplySoup(insertionOffset, hSoup, hWE);
if (err <> noErr) then
goto 1;
_WEForgetHandle(hSoup);
end;
{ determine whether an extra space should be added before or after the inserted text }
intPasteAction := _WEIntelligentPaste(insertionOffset, destEnd, hWE);
{ add the extra space, if necessary }
if (intPasteAction <> weDontAddSpaces) then
begin
space := kSpace;
if (intPasteAction = weAddSpaceOnLeftSide) then
begin
err := _WEInsertText(insertionOffset, @space, 1, hWE);
if (err <> noErr) then
goto 1;
destEnd := destEnd + 1;
{ if an extra space is inserted in front of all dropped items, }
{ don't count it when eventually highlighting the destination range }
if (dragItemIndex = 1) then
destStart := destStart + 1;
end
else
begin
err := _WEInsertText(destEnd, @space, 1, hWE);
if (err <> noErr) then
goto 1;
end;
insertionLength := insertionLength + 1;
_WEAdjustUndoRange(1, hWE);
end; { if extra space }
end
else if (err = badDragFlavorErr) then
begin
{ no text flavor: there must be a flavor matching one of the registered object types }
objectIndex := 0;
while (_WEGetIndObjectType(objectIndex, objectType, hWE) = noErr) do
begin
err := _WEExtractFlavor(theDrag, theItem, objectType, hObjectData, pWE^.translateDragHook);
if (err = noErr) then
Leave; { enclosing while }
if (err <> badDragFlavorErr) then
goto 1;
objectIndex := objectIndex + 1;
end; { while }
if (err <> noErr) then
goto 1;
{ set insertion point on first iteration (*after* extracting flavors, in case we are }
{ doing an intra-window move, otherwise our send proc would be confused) }
if (dragItemIndex = 1) then
begin
pWE^.selStart := insertionOffset;
pWE^.selEnd := insertionOffset;
end;
{ insert the object, but without touching undo or redrawing the text }
saveUndoSupport := WEFeatureFlag(weFUndoSupport, weBitClear, hWE);
saveInhibitRecal := WEFeatureFlag(weFInhibitRecal, weBitSet, hWE);
err := WEInsertObject(objectType, hObjectData, Point(0), hWE);
saveUndoSupport := WEFeatureFlag(weFUndoSupport, saveUndoSupport, hWE);
saveInhibitRecal := WEFeatureFlag(weFInhibitRecal, saveInhibitRecal, hWE);
if (err <> noErr) then
goto 1;
insertionLength := 1;
destEnd := insertionOffset + 1;
pWE^.modCount := pWE^.modCount - 1; { compensate for increment made by WEInsertObject }
_WEAdjustUndoRange(1, hWE);
end
else
goto 1;
{ advance insertion offset for subsequent drag items, if any }
insertionOffset := insertionOffset + insertionLength;
end; { for }
if (isMove) then
begin
{ adjust source range }
if (isBackwards) then
begin
delta := delta - pWE^.textLength;
sourceStart := sourceStart - delta;
sourceEnd := sourceEnd - delta;
end;
{ extend range according to intelligent cut-and-paste rules }
_WEIntelligentCut(sourceStart, sourceEnd, hWE);
{ if undo support is enabled, create a new action so we'll be able to undo the deletion }
if (BTST(pWE^.flags, weFUndoSupport)) then
if (WENewAction(sourceStart, sourceEnd, 0, weAKDrag, 0, hWE, hAction) = noErr) then
if (WEPushAction(hAction) <> noErr) then
;
{ delete source range }
delta := pWE^.textLength;
err := _WEDeleteRange(sourceStart, sourceEnd, hWE);
if (err <> noErr) then
goto 1;
{ adjust destination range }
if (isBackwards = false) then
begin
delta := delta - pWE^.textLength;
destStart := destStart - delta;
destEnd := destEnd - delta;
end;
end; { if isMove }
{ select the range encompassing all items dropped }
pWE^.selStart := destStart;
pWE^.selEnd := destEnd;
{ redraw the text }
if (isMove) then
if (sourceStart < destStart) then
err := _WERedraw(sourceStart, destEnd, hWE)
else
err := _WERedraw(destStart, sourceEnd, hWE)
else
err := _WERedraw(destStart, destEnd, hWE);
1:
{ return result code }
WEReceiveDrag := err;
{ dispose of temporary handles }
_WEForgetHandle(hText);
_WEForgetHandle(hStyles);
_WEForgetHandle(hSoup);
{ restore the port }
SetPort(savePort);
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WEReceiveDrag }
function _WESendFlavor (theType: FlavorType;
dragSendRefCon: Ptr;
hWE: WEHandle;
theDrag: DragReference): OSErr;
label
1;
var
pWE: WEPtr;
selStart, selEnd: LongInt;
hObjectDesc: WEObjectDescHandle;
hItem: Handle;
disposeItem: Boolean;
err: OSErr;
begin
pWE := hWE^;
selStart := pWE^.selStart;
selEnd := pWE^.selEnd;
disposeItem := false;
hItem := nil;
{ see if the selection contains an embedded object whose type matches the flavor type }
if (WEGetSelectedObject(hObjectDesc, hWE) = noErr) & (hObjectDesc^^.objectType = theType) then
hItem := hObjectDesc^^.objectDataHandle
else
begin
{ allocate a temporary handle to hold a copy of the requested flavor }
err := _WEAllocate(0, kAllocTemp, hItem);
if (err <> noErr) then
goto 1;
disposeItem := true; { dispose of hItem when done }
{ identify the requested flavor type as either 'TEXT', 'styl' or 'SOUP' }
if (theType = kTypeText) then
err := WECopyRange(selStart, selEnd, hItem, nil, nil, hWE)
else if (theType = kTypeStyles) then
err := WECopyRange(selStart, selEnd, nil, hItem, nil, hWE)
else if (theType = kTypeSoup) then
err := WECopyRange(selStart, selEnd, nil, nil, hItem, hWE)
else
err := badDragFlavorErr;
if (err <> noErr) then
goto 1;
end;
{ set the drag flavor data }
HLock(hItem);
err := SetDragItemFlavorData(theDrag, ItemReference(hWE), theType, hItem^, GetHandleSize(hItem), 0);
HUnlock(hItem);
1:
{ return result code }
_WESendFlavor := err;
{ clean up }
if (disposeItem) then
_WEForgetHandle(hItem);
end; { _WESendFlavor }
function WEDraggedToTrash (theDrag: DragReference): Boolean;
{ return TRUE if the drop location of the specified drag is the trash }
label
1;
const
bDirectoryAttr = 4;
var
dropLocation, coercedDropLocation: AEDesc;
pb: CInfoPBRec;
pSpec: FSSpecPtr;
trashVRefNum: Integer;
trashDirID: LongInt;
begin
WEDraggedToTrash := false;
dropLocation.dataHandle := nil;
coercedDropLocation.dataHandle := nil;
{ get drop location }
if (GetDropLocation(theDrag, dropLocation) <> noErr) then
goto 1;
{ do nothing if dropLocation is a null descriptor }
if (dropLocation.descriptorType = typeNull) then
goto 1;
{ try to coerce the descriptor to a file system specification record }
if (AECoerceDesc(dropLocation, typeFSS, coercedDropLocation) <> noErr) then
goto 1;
{ lock the data handle of the coerced descriptor }
HLock(coercedDropLocation.dataHandle);
pSpec := FSSpecHandle(coercedDropLocation.dataHandle)^;
{ determine the directory ID of the drop location (assuming it's a folder!) }
_WEBlockClr(@pb, SizeOf(pb));
pb.ioVRefNum := pSpec^.vRefNum;
pb.ioDirID := pSpec^.parID;
pb.ioNamePtr := @pSpec^.name;
if (PBGetCatInfoSync(@pb) <> noErr) then
goto 1;
{ make sure the specified file system object is really a directory }
if (not BTST(pb.ioFlAttrib, bDirectoryAttr)) then
goto 1;
{ find the directory ID of the trash folder }
if (FindFolder(pSpec^.vRefNum, kTrashFolderType, kDontCreateFolder, trashVRefNum, trashDirID) <> noErr) then
goto 1;
{ compare the two directory IDs: if they're the same, the drop location is the trash }
if (pb.ioDrDirID = trashDirID) then
WEDraggedToTrash := true;
1:
{ clean up }
if (AEDisposeDesc(dropLocation) <> noErr) then
;
if (AEDisposeDesc(coercedDropLocation) <> noErr) then
;
end; { WEDraggedToTrash }
function _WEDrag (mouseLoc: Point;
modifiers: Integer;
clickTime: LongInt;
hWE: WEHandle): OSErr;
label
1;
var
pWE: WEPtr;
theDrag: DragReference;
hObjectDesc: WEObjectDescHandle;
theEvent: EventRecord;
dragRgn, tmpRgn: RgnHandle;
dragBounds: Rect;
portDelta: Point;
savePort: GrafPtr;
err: OSErr;
begin
theDrag := kNullDrag;
dragRgn := nil;
tmpRgn := nil;
pWE := hWE^;
{ set up the port }
GetPort(savePort);
SetPort(pWE^.port);
{ fabricate an EventRecord for TrackDrag }
theEvent.what := mouseDown;
theEvent.message := 0;
theEvent.when := clickTime;
theEvent.where := mouseLoc;
LocalToGlobal(theEvent.where);
theEvent.modifiers := modifiers;
{ before seeing the dotted outline, the user must move the mouse a certain }
{ distance away from the initial mouse location; this allows a short click in the selection }
{ area to set the insertion point instead of starting a drag-and-drop sequence }
err := noDragErr;
if (WaitMouseMoved(theEvent.where) = false) then
goto 1;
{ create a drag object }
err := NewDrag(theDrag);
if (err <> noErr) then
goto 1;
{$IFC WASTE_DEBUG}
_WEAssert(theDrag <> kNullDrag, 'Zero is a valid drag reference (??)');
{$ENDC}
{ if the selection range consists of an embedded object, }
{ then use its object type as flavor type }
if (WEGetSelectedObject(hObjectDesc, hWE) = noErr) then
begin
err := AddDragItemFlavor(theDrag, ItemReference(hWE), hObjectDesc^^.objectType, nil, 0, 0);
if (err <> noErr) then
goto 1;
end
else
begin
{ add a 'TEXT' flavor to the drag }
err := AddDragItemFlavor(theDrag, ItemReference(hWE), kTypeText, nil, 0, 0);
if (err <> noErr) then
goto 1;
{ add a 'styl' flavor to the drag }
err := AddDragItemFlavor(theDrag, ItemReference(hWE), kTypeStyles, nil, 0, 0);
if (err <> noErr) then
goto 1;
{ add a 'SOUP' flavor to the drag }
err := AddDragItemFlavor(theDrag, ItemReference(hWE), kTypeSoup, nil, 0, 0);
if (err <> noErr) then
goto 1;
end;
{ since we didn't provide the flavor data for any of the above flavors, }
{ we need supply a data send callback }
if (_weFlavorSender = nil) then
_weFlavorSender := NewDragSendDataProc(@_WESendFlavor);
err := SetDragSendProc(theDrag, _weFlavorSender, nil);
if (err <> noErr) then
goto 1;
{ get hilite region }
dragRgn := WEGetHiliteRgn(pWE^.selStart, pWE^.selEnd, hWE);
{ we need just the outline of this region }
tmpRgn := NewRgn;
CopyRgn(dragRgn, tmpRgn);
InsetRgn(tmpRgn, 1, 1);
DiffRgn(dragRgn, tmpRgn, dragRgn);
DisposeRgn(tmpRgn);
{ and we need it in global coordinates }
portDelta := Point(0);
LocalToGlobal(portDelta);
OffsetRgn(dragRgn, portDelta.h, portDelta.v);
{ set the bounds of the drag }
dragBounds := dragRgn^^.rgnBBox;
err := SetDragItemBounds(theDrag, ItemReference(hWE), dragBounds);
if (err <> noErr) then
goto 1;
{ stash drag reference in currentDrag so WETrackDrag and WEReceiveDrag }
{ can tell whether a given drag originated from this WE instance }
pWE^.currentDrag := theDrag;
{ track the drag }
err := TrackDrag(theDrag, theEvent, dragRgn);
pWE^.currentDrag := kNullDrag;
if (err <> noErr) then
goto 1;
{ if the selection was dragged to the trash and the option key wasn't held down }
{ and if the instance is editable, delete the selection }
if (not BTST(pWE^.flags, weFReadOnly)) then
if (WEDraggedToTrash(theDrag)) then
if (_WEIsOptionDrag(theDrag) = false) then
begin
err := WEDelete(hWE);
if (err <> noErr) then
goto 1;
end;
{ clear result code }
err := noErr;
1:
{ return result code }
_WEDrag := err;
{ dispose of the drag }
if (theDrag <> kNullDrag) then
if (DisposeDrag(theDrag) <> noErr) then
;
{ dispose of the drag region }
if (dragRgn <> nil) then
DisposeRgn(dragRgn);
{ restore the port }
SetPort(savePort);
end; { _WEDrag }
{$IFC WASTE_SEGMENT}
{$S}
{$ENDC}
procedure WEClick (mouseLoc: Point;
modifiers: Integer;
clickTime: LongInt;
hWE: WEHandle);
label
1;
var
pWE: WEPtr;
hObjectDesc: WEObjectDescHandle;
thePoint: LongPt;
offset, anchor: LongInt;
rangeStart, rangeEnd: LongInt;
edge: SignedByte;
isMultipleClick: Boolean;
saveWELock: Boolean;
begin
{ stop any ongoing inline input session }
WEStopInlineSession(hWE);
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ hide the caret if it's showing }
if BTST(pWE^.flags, weFCaretVisible) then
_WEBlinkCaret(hWE);
{ find click offset }
WEPointToLongPoint(mouseLoc, thePoint);
offset := WEGetOffset(thePoint, edge, hWE);
{ determine whether this click is part of a sequence }
{ a single click inside an object selects it, so it's like a double click in a word }
isMultipleClick := ((clickTime < pWE^.clickTime + GetDblTime) and (offset = pWE^.clickLoc));
{ remember click time, click offset and edge value }
pWE^.clickTime := clickTime;
pWE^.clickLoc := offset;
pWE^.clickEdge := edge;
{ when selected, embedded objects can intercept mouse clicks }
if (WEGetSelectedObject(hObjectDesc, hWE) = noErr) then
if _WEOffsetInRange(offset, edge, pWE^.selStart, pWE^.selEnd) then
if (_WEClickObject(mouseLoc, modifiers + ORD(isMultipleClick), clickTime, hObjectDesc)) then
goto 1;
if (BAND(modifiers, shiftKey) = 0) then
begin
{ is this click part of a sequence or is it a single click? }
if (isMultipleClick) then
begin
pWE^.clickCount := pWE^.clickCount + 1;
{ a double (triple) click creates an anchor-word (anchor-line) }
if (pWE^.clickCount > 1) then
WEFindLine(offset, edge, pWE^.anchorStart, pWE^.anchorEnd, hWE)
else
WEFindWord(offset, edge, pWE^.anchorStart, pWE^.anchorEnd, hWE);
offset := pWE^.anchorStart;
end
else
begin
{ single-click }
{ if the Drag Manager is available and the click went in the selection range, }
{ this click may be the beginning of a drag gesture }
if (BTST(pWE^.flags, weFHasDragManager) and BTST(pWE^.flags, weFDragAndDrop)) then
if _WEOffsetInRange(offset, edge, pWE^.selStart, pWE^.selEnd) then
if (_WEDrag(mouseLoc, modifiers, clickTime, hWE) <> noDragErr) then
goto 1;
pWE^.clickCount := 0;
anchor := offset;
end
end
else
{ if the shift key was down, use the old anchor offset found with the previous click }
if BTST(pWE^.flags, weFAnchorIsEnd) then
anchor := pWE^.selEnd
else
anchor := pWE^.selStart;
{ set the weFMouseTracking bit while we track the mouse }
BSET(pWE^.flags, weFMouseTracking);
{ MOUSE TRACKING LOOP }
repeat
{ get text offset corresponding to mouse position }
WEPointToLongPoint(mouseLoc, thePoint);
offset := WEGetOffset(thePoint, edge, hWE);
{ if we're selecting words or lines, pin offset to a word or line boundary }
if (pWE^.clickCount > 0) then
begin
if (pWE^.clickCount > 1) then
WEFindLine(offset, edge, rangeStart, rangeEnd, hWE)
else
WEFindWord(offset, edge, rangeStart, rangeEnd, hWE);
{ choose the word/line boundary and the anchor that are farthest away from each other }
if (offset > pWE^.anchorStart) then
begin
anchor := pWE^.anchorStart;
offset := rangeEnd;
end
else
begin
offset := rangeStart;
anchor := pWE^.anchorEnd;
end;
end
else
{ if the point is in the middle of an object, the selection should include it }
if (edge = kObjectEdge) then
offset := offset + 1;
{ set the selection range from anchor point to current offset }
WESetSelection(anchor, offset, hWE);
{ call the click loop callback, if any }
if (pWE^.clickLoop <> nil) then
if (CallWEClickLoopProc(hWE, pWE^.clickLoop) = false) then
Leave;
{ update mouse position }
GetMouse(mouseLoc);
until (not WaitMouseUp);
{ clear the weFMouseTracking bit }
BCLR(pWE^.flags, weFMouseTracking);
{ redraw the caret immediately if the selection range is empty }
if (anchor = offset) then
_WEBlinkCaret(hWE);
1:
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WEClick }
end.